/* LCD module */#include <p18cxxx.h>#include <delays.h>#include "define.h"/* LCD display lines */#define L0_p1 0x80 /** Line 0 (upper line) with positions 1 to 16 */#define L0_p2 0x81#define L0_p3 0x82#define L0_p4 0x83#define L0_p5 0x84#define L0_p6 0x85#define L0_p7 0x86#define L0_p8 0x87#define L0_p9 0x88#define L0_p10 0x89#define L0_p11 0x8A#define L0_p12 0x8B#define L0_p13 0x8C#define L0_p14 0x8D#define L0_p15 0x8E#define L0_p16 0x8F#define L1_p1 0xC0 /** Line 1 (bottom line) with positions 1 to 16 */#define L1_p2 0xC1#define L1_p3 0xC2#define L1_p4 0xC3#define L1_p5 0xC4#define L1_p6 0xC5#define L1_p7 0xC6#define L1_p8 0xC7#define L1_p9 0xC8#define L1_p10 0xC9#define L1_p11 0xCA#define L1_p12 0xCB#define L1_p13 0xCC#define L1_p14 0xCD#define L1_p15 0xCE#define L1_p16 0xCF/* Register selection and Read/Write inputs */#define READ 1 /** Read Operation */#define WRITE 0 /** Write Operation */#define INSTR 0 /** Instruction register is selected */#define DATA 1 /** Data Register is selected *//* LCD settings */#define FUNCTION_SET 0x38 /** 8 bit bus, 2 lines */#define DISPLAY_OFF 0x08 /** Display control BitD is low. Entire display is turned off. Bit3 set*/#define DISPLAY_ON 0x0F /** Display control BitD is high. Entire display is turned on. Bit3 set. Cursor control bit and blink bit are set to high(turned on)*/#define CLEAR_DISPLAY 0x01 /** Clear all the display data. Bit0 set */#define ENTRY_MODE 0x06 /** Increment mode, Entire display Shift off, Bit2 set *//* PSP pins */#define LCD_DATA PORTD /** LCD 8 data bits */#define LCD_D_DIR TRISD /** PORTD Data direction register. Setting a TRISD bit(=1) will make the corresponding PORTD pin an input, while clearing it (=0) will make the pin an output */#define LCD_RS PORTEbits.RE0 /** LCD Register Select control line */#define LCD_RS_DIR TRISEbits.TRISE0 /** Register Select Direction Control bit. 1=Input, 0=Output.*/#define LCD_RW PORTEbits.RE1 /** LCD Read/Write control line */#define LCD_RW_DIR TRISEbits.TRISE1 /** Read/Write Direction Control bit. 1=Input, 0=Output.*/#define LCD_E PORTEbits.RE2 /** LCD Enable control line */#define LCD_E_DIR TRISEbits.TRISE2 /** Enable Direction Control bit. 1=Input, 0=Output.*//* Variables */char LCDBuffer[O_BUFSIZE];/** Output buffer */unsignedchar writeIndex =0;/** Write Index for buffer */unsignedchar readIndex =0;/** Read Index for buffer */unsignedchar LCDWantsToSend = FALSE;/** Flag indicating data to be sent *//* Prototypes */void initialise_LCD (void);void Instruction_LCD(unsignedchar value);void BF_LCD(void);unsignedchar get_DDRAM (void);void putchar_LCD (unsignedchar cval);void send_LCD (unsignedchar dispval);void string_LCD(unsignedchar*pointer);void sendNext(void);unsignedchar isBusy(void);/**
* Function that initialises the LCD by instruction to an 8-bit interface mode.
* @pre LCD has power.
*/void initialise_LCD (void){
TRISE =0x00;/* Configuration for output on PORTD and PORTE */
TRISD =0x00;
ADCON1 =0b00000110;/* The A/D port configuration bits PCFG2:PCFG0 (ADCON1<2:0>) SET,to configure pins RE2:RE0 as digital I/O */
PORTD =0x00;
LCD_E_DIR =0;
LCD_RS_DIR =0;
LCD_RW_DIR =0;/* Initialisation using delays.h */
Delay1KTCYx(120);/* Power on delay of 30ms */
Instruction_LCD(FUNCTION_SET);/* 8 bit interface, 2-lines */
Delay10TCYx(16);/* Delay of 39 microseconds */
Instruction_LCD(DISPLAY_ON);/* display, cursor and blink on */
Delay10TCYx(16);/* Delay of 39 microseconds */
Instruction_LCD(CLEAR_DISPLAY);/* Clear the display and return cursor home */
Delay100TCYx(62);/* Delay of 1.53 ms */
Instruction_LCD(ENTRY_MODE);/* Entry Mode Sets: cursor moves to the righ and display appears stationary */}/**
* Function that sends an instruction to the LCD.
* @param value The command character to send
* @pre LCD has been initialised
*/void Instruction_LCD(unsignedchar value){
BF_LCD();/* check through Busy Flag that the LCD is ready to go */
LCD_RS = INSTR;/* selects Instruction register (IR) */
LCD_RW = WRITE;/* Sets write mode */
LCD_E =1;/* Enable signal */
LCD_DATA = value;/* send out the command */
Nop();
LCD_E =0;/* external write cycle is complete */}/**
* Function that detects the LCD Busy Flag(BF)before executing the next instrunction.
* @pre The LCD must be initalised.
* @post The LCD is not busy.
*/void BF_LCD(void){char check_bf =1;
LCD_D_DIR =0xFF;/* configure LCD data bus for input */
LCD_RS = INSTR;/* Set LCD for instruction mode (IR) */
LCD_RW = READ;/* Set to read busy flag */while(check_bf){
LCD_E =1;/* Enable signal */
check_bf = LCD_DATA;/* Read busy flag + DDram address */
LCD_E =0;/* complete a read cycle */
check_bf = check_bf &0x80;/* check Busy Flag, Busy = 1. DBit7 used for Busy Flag output */}
LCD_D_DIR =0x00;/* configure LCD data bus for output */}/**
* Function that reads the DDRAM value.
* @return The DDRAM data bits 0-6
* @pre The LCD must be initalised.
*/unsignedchar get_DDRAM (void){char temp;
LCD_D_DIR =0xFF;/* configure LCD data port for input */
LCD_RS = INSTR;/* select IR register */
LCD_RW = READ;/* setup to read busy flag */
LCD_E =1;/* LCD E-line to high */
temp = LCD_DATA &0x7F;/* read DDRAM address and set busy flag to low */
LCD_E =0;/* LCD E-line to low */return temp;}/**
* Function that sends character to send_LCD. It toggles the data between the top and bottom display lines of the LCD.
* The 'end of line' symbol sets the data to display in the bottom row, whilst the 'carriage return' symbol sets it back to the top one.
* @param cval The character to be sent.
* @pre LCD is fully initialised
*/void putchar_LCD (unsignedchar cval){
BF_LCD();/* Wait for LCD to be ready */if(cval =='\n')/* Line feed means set to row 2 */{
Instruction_LCD(L1_p1);/* set cursor to column 1 row 2 */return;}if(cval =='\r')/* Carriage return means set to row 1 */{
Instruction_LCD(L0_p1);/* set cursor to column 1 row 1 */return;}
send_LCD(cval);}/**
* Function that transmits a character to LCD.
* @param dispval The character to be sent.
* @pre The LCD must not be busy and it must be initialised.
* @post The LCD busy flag is set until it finishes
*/void send_LCD (unsignedchar dispval){
LCD_RS = DATA;/* Set LCD in data mode */
LCD_RW = WRITE;/* Set LCD in write mode */
LCD_E =1;/* LCD E-line High */
LCD_DATA = dispval;/* Send data to LCD */
LCD_E =0;/* LCD E-line to Low */}/**
* Stores a string in the LCDbuffer to be sent to the LCD.
* Notes: Calling this method to rapidly with too much data will cause
* the buffer to overflow, and data may not be transmitted properly.
* @param pointer The unsigned char* pointing to the string.
* @pre The LCD is properly initialised
* @post The string is added to the LCDbuffer
*/void string_LCD(unsignedchar* pointer){while(*pointer !='\0'){
LCDBuffer[writeIndex]=*pointer;
writeIndex ++;if(writeIndex == O_BUFSIZE)/* End of circular buffer */{
writeIndex =0;/* Loop round */}
pointer++;/* Next char */}
LCDWantsToSend = TRUE;}/**
* Sends the next character stored in the LCDBuffer.
* @pre The LCD is not busy. Important to check this first.
* @post The character is sent, and the buffer moves along. If there are no more characters to send in the buffer, then LCDWantsToSend will be
* set to FALSE.
*/void sendNext(void){if(!LCDWantsToSend)return;/* If there's nothing to send, don't. */
putchar_LCD(LCDBuffer[readIndex]);
readIndex++;if(readIndex == O_BUFSIZE)/* End of circular buffer */{
readIndex =0;/* Loop round */}if(readIndex == writeIndex)/* If the read catches up with the write */{
LCDWantsToSend = FALSE;}}/**
* Gets whether or not the LCD is busy
* @return boolean An unsigned char of 0 or !0 (specifically 0x80)
*/unsignedchar isBusy(void){char check_bf =1;
LCD_D_DIR =0xFF;/* configure LCD data bus for input */
LCD_RS = INSTR;/* Set LCD for instruction mode (IR) */
LCD_RW = READ;/* Set to read busy flag */
LCD_E =1;/* Enable signal */
check_bf = LCD_DATA;/* Read busy flag + DDram address */
LCD_E =0;/* complete a read cycle */
check_bf = check_bf &0x80;/* check Busy Flag, Busy = 1. DBit7 used for Busy Flag output */
LCD_D_DIR =0x00;/* configure LCD data bus for output */return check_bf;/* check_bf = 0 or 0x80 */}